// 交叉类型
interface Person { name: string }
interface Concat { phone: string }
type PersonDetail = Person & Concat
let obj: PersonDetail = {
    name: '同花顺',
    phone: 'iphone99999'

}
// 相当于interface PersonDetail{name:string;phone:string}

// 交叉类型（&）和接口继承（extends）的对比
// 相同点：都可以实现对象类型的组合
// 不同点：对于同名属性之间的处理方式不同
// 用extends,当同名的属性类型不一样,会报错  这个用于interface 接口的继承

// 使用交叉类型如果同名的类型不一致不会报错
interface A {
    fn: (value: string) => string
}
interface B {
    fn: (value: number) => string
}
type C = A & B
//相当于 fn:(value:number | string)=>sting

// 泛型 
// 语法 在函数名称后面加上<类型变量> Type
// 创建泛型函数
function id<Type>(value: Type): Type { return value }
// 调用的时候需要用<>添加类型
const num = id<number>(10)
// 可以简写，由于具有类型推断机制，可以将调用函数的<>省去
let str = id('a') //会提示一个字面量的类型，更加的精确，也可以自己用<>添加

// 如果在使用泛型的时候，接收的参数知道是数组，可以在参数的type后面加上[]
function Id<Type>(value: Type[]): Type[] {
    console.log(value.length)//可以使用数组所带的属性
    return value
}
console.log(Id(['a', 'b']));

//   添加约束
interface Ilength {
    length: number
}
function IId<Type extends Ilength>(value: Type) { //这样将不能传入没有length属性的值
    return value
}
// 注意：这里的extends不是继承，而是Type中一定要有Ilength这个属性，这样一后的数组和字符串类型的数据就可以访问length属性，这样就添加了约束
function DD<Type, Key extends keyof Type>(obj: Type, key: Key) { //Key添加了约束，只能是Type这个对象中的数据
    return obj[key]
}
let Obj = { name: 'jack', age: 18 }
DD(Obj, 'name')

// 泛型接口
// 可以为接口添加一个Type
interface IdFun<Type> {
    fu: (value: Type) => Type
    sa: () => Type[]
    b:()=>void
}
let Idobj: IdFun<number> = {
    fu(value){ return value },
     sa(){
        return [1,3,5]
     },
     b(){}
}
console.log(Idobj.fu(2));

// 创建泛型类
class GenericNumber<NumType>{
    default:NumType
    add:(x:NumType,y:NumType)=>NumType
}
//在创建实例对象时，需要指定类型
const myNum=new GenericNumber<number>()
myNum.default=20
// 泛型工具
interface Props{
    name:string
    children:string
}
type PartialProps=Partial<Props>//这时Props中的类型在PartialProps中是可选的

// 只读类型 Readonly<Type>
type ReadonlyProps=Readonly<Props>
let props:ReadonlyProps={name:'张三',children:'erzi'}//只能在这里赋值，其他的地方都不能赋值
// props.name='lisi'

// 选择类型
type PickProps=Pick<Props,'name'| 'children'>
let props1:PickProps={
    name:'lisi',
    children:'wangwu'
}

// 构造对象类型
type RecordkObj=Record<'a'|'b'|'c',string[]>//字符串数组
let Obj2:RecordkObj={
    a:['a'],
    b:['b'],
    c:['c']
}

type abc = keyof {a: 1, b: 2}

const appp: abc = 'b'
